/*
 Copyright (C) 2025 Kristian Duske

 This file is part of TrenchBroom.

 TrenchBroom is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 TrenchBroom is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
 */

#include "io/EntityDefinitionClassInfo.h"
#include "mdl/EntityDefinition.h"
#include "mdl/EntityDefinitionUtils.h"
#include "mdl/EntityProperties.h"
#include "mdl/PropertyDefinition.h"

#include "catch/CatchConfig.h"

#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>

namespace tb::mdl
{

TEST_CASE("addOrSetDefaultEntityLinkProperties")
{
  using namespace EntityPropertyKeys;

  static const auto targetDefinition = PropertyDefinition{
    Target,
    mdl::PropertyValueTypes::LinkSource{},
    "name of entity to trigger",
    "generated by TrenchBroom"};
  static const auto killtargetDefinition = PropertyDefinition{
    Killtarget,
    mdl::PropertyValueTypes::LinkSource{},
    "name of entity to kill",
    "generated by TrenchBroom"};
  static const auto targetnameDefinition = PropertyDefinition{
    Targetname,
    mdl::PropertyValueTypes::LinkTarget{},
    "target name for linking",
    "generated by TrenchBroom"};

  using T = std::tuple<std::vector<EntityDefinition>, std::vector<EntityDefinition>>;

  const auto [originalDefinitions, expectedDefinitions] = GENERATE(values<T>({
    {{}, {}},
    {{
       {"some_definition", {}, "", {}},
     },
     {
       {"some_definition",
        {},
        "",
        {
          targetDefinition,
          killtargetDefinition,
          targetnameDefinition,
        }},
     }},
    {{
       {"some_definition",
        {},
        "",
        {
          {"some_key", mdl::PropertyValueTypes::String{}, "", ""},
          {Target, mdl::PropertyValueTypes::String{}, "", ""},
          {Killtarget, mdl::PropertyValueTypes::String{}, "", ""},
          {Targetname, mdl::PropertyValueTypes::String{}, "", ""},
        }},
     },
     {
       {"some_definition",
        {},
        "",
        {
          {"some_key", mdl::PropertyValueTypes::String{}, "", ""},
          {Target, mdl::PropertyValueTypes::LinkSource{}, "", ""},
          {Killtarget, mdl::PropertyValueTypes::LinkSource{}, "", ""},
          {Targetname, mdl::PropertyValueTypes::LinkTarget{}, "", ""},
        }},
     }},
    {{
       {"some_definition",
        {},
        "",
        {
          {"some_key", mdl::PropertyValueTypes::String{}, "", ""},
          {Target, mdl::PropertyValueTypes::LinkSource{}, "", ""},
        }},
       {"some_other_definition",
        {},
        "",
        {
          {"some_key", mdl::PropertyValueTypes::String{}, "", ""},
          {Target, mdl::PropertyValueTypes::String{}, "", ""},
          {Killtarget, mdl::PropertyValueTypes::String{}, "", ""},
          {Targetname, mdl::PropertyValueTypes::String{}, "", ""},
        }},
     },
     {
       {"some_definition",
        {},
        "",
        {
          {"some_key", mdl::PropertyValueTypes::String{}, "", ""},
          {Target, mdl::PropertyValueTypes::LinkSource{}, "", ""},
        }},
       {"some_other_definition",
        {},
        "",
        {
          {"some_key", mdl::PropertyValueTypes::String{}, "", ""},
          {Target, mdl::PropertyValueTypes::String{}, "", ""},
          {Killtarget, mdl::PropertyValueTypes::String{}, "", ""},
          {Targetname, mdl::PropertyValueTypes::String{}, "", ""},
        }},
     }},
  }));

  CAPTURE(originalDefinitions);

  auto definitions = originalDefinitions;
  addOrSetDefaultEntityLinkProperties(definitions);

  CHECK(definitions == expectedDefinitions);
}

TEST_CASE("addOrConvertOriginProperties")
{
  using namespace EntityPropertyKeys;
  using namespace PropertyValueTypes;

  using T = std::tuple<std::vector<EntityDefinition>, std::vector<EntityDefinition>>;

  const auto [originalDefinitions, expectedDefinitions] = GENERATE(values<T>({
    {{}, {}},
    {{
       {"some_brush_definition", {}, "", {}},
     },
     {
       {"some_brush_definition", {}, "", {}},
     }},
    {{
       {"point_definition_no_origin", {}, "", {}, PointEntityDefinition{}},
     },
     {
       {"point_definition_no_origin",
        {},
        "",
        {PropertyDefinition{
          "origin",
          PropertyValueTypes::Origin{},
          "point entity origin",
          "generated by TrenchBroom"}},
        PointEntityDefinition{}},
     }},
    {{
       {"point_definition_string_origin",
        {},
        "",
        {PropertyDefinition{"origin", PropertyValueTypes::String{}, {}, {}}},
        PointEntityDefinition{}},
     },
     {
       {"point_definition_string_origin",
        {},
        "",
        {PropertyDefinition{"origin", PropertyValueTypes::Origin{}, {}, {}}},
        PointEntityDefinition{}},
     }},
    {{
       {"point_definition_string_origin_with_default",
        {},
        "",
        {PropertyDefinition{"origin", PropertyValueTypes::String{"1 2 3"}, {}, {}}},
        PointEntityDefinition{}},
     },
     {
       {"point_definition_string_origin_with_default",
        {},
        "",
        {PropertyDefinition{"origin", PropertyValueTypes::Origin{"1 2 3"}, {}, {}}},
        PointEntityDefinition{}},
     }},
  }));

  CAPTURE(originalDefinitions);

  auto definitions = originalDefinitions;
  addOrConvertOriginProperties(definitions);

  CHECK(definitions == expectedDefinitions);
}

} // namespace tb::mdl
